.SECONDEXPANSION:
SHELL:=/bin/bash
SOURCE_PATH := src
TMP_PATH := tmp
BUILD_PATH := build
PREFIX_PATH := $(shell echo $${prefix_path:-/usr})
USER := $(shell echo $${user:-root})

CFLAGS:=-fPIC -Wall -I${SOURCE_PATH}
LDFLAGS:=-shared

EXECUTABLES_TARGETS:=
HEADERS_TARGETS:=cexceptions
LIBRARIES_TARGETS:=cexceptions

INSTALLABLE_FILES:=$(foreach target,${LIBRARIES_TARGETS},lib/lib${target}.so) $(foreach target,${HEADERS_TARGETS},$(patsubst ${SOURCE_PATH}/${target}/%,include/${target}/%,$(wildcard ${SOURCE_PATH}/${target}/*.h)))
INSTALLABLE_FILES_DEV:=${INSTALLABLE_FILES} $(foreach target,${HEADERS_TARGETS},$(patsubst ${SOURCE_PATH}/${target}/%,include/${target}/%,$(wildcard ${SOURCE_PATH}/${target}/.*.h)))

define get_target_objects =
$(patsubst ${SOURCE_PATH}/%.c,${TMP_PATH}/%.o,$(wildcard ${SOURCE_PATH}/${1}/*.c))
endef

define get_target_headers =
$(patsubst ${SOURCE_PATH}/%,${BUILD_PATH}/include/%,$(wildcard ${SOURCE_PATH}/${1}/*.h))
endef

define get_target_dev_headers =
$(patsubst ${SOURCE_PATH}/%,${BUILD_PATH}/include/%,$(wildcard ${SOURCE_PATH}/${1}/.*.h))
endef

.PHONY: all all-dev clean remove-build rebuild rebuild-dev install install-dev uninstall list-files

${TMP_PATH}:
	@[ -d "${TMP_PATH}" ] || mkdir -p "${TMP_PATH}"
${BUILD_PATH}:
	@[ -d "${BUILD_PATH}" ] || mkdir -p "${BUILD_PATH}"
all: ${LIBRARIES_TARGETS} ${HEADERS_TARGETS}
all-dev: $(foreach target,${LIBRARIES_TARGETS} ${HEADERS_TARGETS},${target}-dev)
clean:
	@([ -d "${TMP_PATH}" ] && rm -r "${TMP_PATH}") || true
remove-build:
	@([ -d "${BUILD_PATH}" ] && rm -r "${BUILD_PATH}") || true
rebuild: remove-build all
rebuild-dev: remove-build all-dev
install: all
	@sudo -u ${USER} -k bash -c "[ -d \"${PREFIX_PATH}\" ] || mkdir -p \"${PREFIX_PATH}\"; >&2 echo Installing $^; cp -r -t \"${PREFIX_PATH}\" \"${BUILD_PATH}\"/*"
install-dev: all-dev
	@sudo -u ${USER} -k bash -c "[ -d \"${PREFIX_PATH}\" ] || mkdir -p \"${PREFIX_PATH}\"; >&2 echo Installing $^; cp -r -t \"${PREFIX_PATH}\" \"${BUILD_PATH}\"/*"
uninstall:
	@sudo -u ${USER} -k bash -c ">&2 echo Uninstalling; rm -f $(foreach installed,${INSTALLABLE_FILES_DEV},${PREFIX_PATH}/${installed})"
reinstall: uninstall install
reinstall-dev: uninstall install-dev
list-files:
	@>&2 echo "Installable:"
	@for file in ${INSTALLABLE_FILES} ; do echo "$${file}" ; done
list-files-dev:
	@>&2 echo "Installable:"
	@for file in ${INSTALLABLE_FILES_DEV} ; do echo "$${file}" ; done
$(filter %,${EXECUTABLES_TARGETS}):%:${BUILD_PATH}/bin/%
$(filter %,${LIBRARIES_TARGETS}):%:${BUILD_PATH}/lib/lib%.so
$(filter %,${LIBRARIES_TARGETS})-dev:%-dev:%
$(filter %,${HEADERS_TARGETS}):%:$$(call get_target_headers,$$*)
$(filter %,${HEADERS_TARGETS})-dev:%-dev:% $$(call get_target_dev_headers,$$*)

${BUILD_PATH}/include/%.h: ${SOURCE_PATH}/%.h
	@echo Copying $*.h
	@[ -d "$(shell dirname "${@}")" ] || mkdir -p "$(shell dirname "${@}")"
	@cp -t "$(shell dirname "${@}")" "$^"
	@chmod 0664 "${@}"

${BUILD_PATH}/lib/lib%.so: ${BUILD_PATH} $$(call get_target_objects,$$*)
	@[ -d "$(shell dirname "${@}")" ] || mkdir -p "$(shell dirname "${@}")"
	@#${AR} rcs "${@}" $(filter-out $<,$^) && ranlib "${@}"
	@echo Building lib/lib$*.so
	@${CC} ${LDFLAGS} -o $@ $(filter-out $<,$^)
	@chmod 0775 "${@}"

${TMP_PATH}/%.o: ${TMP_PATH} ${SOURCE_PATH}/%.c
	@[ -d "$(shell dirname "$@")" ] || mkdir -p "$(shell dirname "$@")"
	@echo Compiling $*.o
	@${CC} -c ${CFLAGS} -o "${@}" $(filter-out $<,$^)
